/*
 * Copyright 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kira.solo.schedule.utils

import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter

inline fun <reified T> jsonSerializer(
    noinline defaultProvider: () -> T
): JsonSerializer<T> = JsonSerializer(
    serializer = { Json.encodeToString(it) },
    deserializer = { Json.decodeFromString(it) },
    defaultProvider = defaultProvider
)

/**
 * Serializer for json object.
 * 采用字符串的方式进行序列化，在json字符串过长时，会大量占用内存，在android上会表现为crash。
 * 目前1.0版本的kotlinx.serialization不支持流的方式进行json序列化和反序列化。
 * kotlinx.serialization计划在1.1或者1.2版本加入对Kotin-io的支持。
 * 参见:https://github.com/Kotlin/kotlinx.serialization/issues/204。
 *
 */
class JsonSerializer<T>(
    private val serializer: (T) -> String,
    private val deserializer: (String) -> T,
    private val defaultProvider: () -> T,
) : Serializer<T> {
    override val defaultValue: T
        get() = defaultProvider()

    override suspend fun readFrom(input: InputStream): T {
        try {
            return deserializer(InputStreamReader(input).readText())
        } catch (e: SerializationException) {
            throw CorruptionException("Cannot read json.", e)
        }
    }

    override suspend fun writeTo(t: T, output: OutputStream) {
        val json = serializer(t)
        val osw = OutputStreamWriter(output)
        osw.write(json)
        osw.flush()
    }
}

inline fun <T, reified R> jsonSerializer(
    noinline readTrans: (R) -> T,
    noinline writeTrans: (T) -> R,
    noinline defaultProvider: () -> T
): JsonSerializer<T> = JsonSerializer(
    serializer = {
        val json = writeTrans(it)
        Json.encodeToString(json)
    },
    deserializer = {
        val json = Json.decodeFromString<R>(it)
        readTrans(json)
    },
    defaultProvider = defaultProvider
)


class FixedSerializer<T>(
    private val defaultProvider: () -> T,
) : Serializer<T> {
    override val defaultValue: T
        get() = defaultProvider()

    override suspend fun readFrom(input: InputStream): T = defaultValue

    override suspend fun writeTo(t: T, output: OutputStream) = Unit
}